package parser

import (
	"fmt"
	"go/token"
	"reflect"
	"strconv"
	"strings"
)

type Error struct {
	Pos token.Position
	Tok token.Token
	Sss string
	Msg string
}

func (err *Error) Error() string {
	return err.Pos.String() + " : " + err.Msg
}

type SLabel struct {
	Rfnm string
}

type SArray struct {
	Vals []interface{}
}

/* map??? */
type SStruct struct {
	Sname  string
	Fields map[string]interface{}
}

type SExpre struct {
	Ident string
	Vval  interface{}
	Pos   token.Position
}

type Parser struct {
	lex *Lexical

	/**/
	Expres []*SExpre
}

func NewParser(fname string) (*Parser, error) {
	lex, err := NewLexical(fname)
	if err != nil {
		return nil, err
	}
	par := &Parser{lex, nil}
	return par, nil
}

func (ps *Parser) GoThrou() ([]*SExpre, error) {
	var pos token.Pos
	var tok token.Token
	var sss string
	var idt string
	var stn string
	var fin token.Position

	for {

		/* skip ln and ??*/
		pos, tok, sss = ps.lex.Next(skipNone)
		//fmt.Printf("%v\t%s\t%q\n", pos, tok, sss)

		if tok == token.EOF {
			break
		}

		/**/
		if tok != token.IDENT {
			return nil, &Error{ps.lex.Position(pos), tok, sss, "must a ident at begin"}
		}
		idt = sss
		fin = ps.lex.Position(pos)

		/**/
		pos, tok, sss = ps.lex.Next(skipNone)
		if tok != token.ASSIGN {
			return nil, &Error{ps.lex.Position(pos), tok, sss, "must assign op"}
		}

		/* value : struct or simple */
		pos, tok, sss = ps.lex.Next(skipNone)
		if tok == token.IDENT {
			stn = sss
			/* struct or ident */
			pos, tok, sss = ps.lex.Next(skipNone)
			if tok == token.LBRACE {
				ttt, perr := ps.expectStruct(stn)
				if perr != nil {
					return nil, perr
				}

				ps.Expres = append(ps.Expres, &SExpre{idt, ttt, fin})

			} else {
				/* variable reference */
				ps.lex.Back()
				rfv := &SLabel{stn}
				ps.Expres = append(ps.Expres, &SExpre{idt, rfv, fin})
			}

		} else {

			ps.lex.Back()
			vvv, perr := ps.expectValue()
			if perr != nil {
				return nil, perr
			}

			/**/
			ps.Expres = append(ps.Expres, &SExpre{idt, vvv, fin})
		}

		/* check semicolon, skip.. */
		pos, tok, sss = ps.lex.Next(skipSMC)
		ps.lex.Back()
	}

	return ps.Expres, nil
}

func (ps *Parser) expectValue() (interface{}, *Error) {

	var pos token.Pos
	var tok token.Token
	var sss string

	/**/
	pos, tok, sss = ps.lex.Next(skipNone)

	switch tok {

	case token.IDENT:
		/* variable reference */
		return &SLabel{sss}, nil

	case token.STRING:
		sss = strings.Trim(sss, "\"")
		return &sss, nil

	case token.INT:
		ii, err := strconv.ParseInt(sss, 0, 64)
		if err != nil {
			return nil, &Error{ps.lex.Position(pos), tok, sss, err.Error()}
		}
		return &ii, nil

	case token.FLOAT:
		ff, err := strconv.ParseFloat(sss, 64)
		if err != nil {
			return nil, &Error{ps.lex.Position(pos), tok, sss, err.Error()}
		}
		return &ff, nil

	case token.LBRACK:
		/* array ?? */
		ary, perr := ps.expectArray()
		if perr != nil {
			return nil, perr
		}
		return ary, nil

	default:
		return nil, &Error{ps.lex.Position(pos), tok, sss, "not simple value"}
	}
}

func (ps *Parser) expectStruct(idt string) (*SStruct, *Error) {
	var pos token.Pos
	var tok token.Token
	var sss string
	var fnm string

	/**/
	ttt := &SStruct{idt, make(map[string]interface{})}

	for {
		pos, tok, sss = ps.lex.Next(skipNone)

		if tok == token.RBRACE {
			break
		}

		/**/
		if tok != token.IDENT {
			return nil, &Error{ps.lex.Position(pos), tok, sss, "field name in struct"}
		}

		/**/
		fnm = sss

		/**/
		pos, tok, sss = ps.lex.Next(skipNone)
		if tok != token.COLON {
			return nil, &Error{ps.lex.Position(pos), tok, sss, "must colon op"}
		}

		/**/
		val, perr := ps.expectValue()
		if perr != nil {
			return nil, perr
		}

		if ttt.Fields[fnm] != nil {
			return nil, &Error{ps.lex.Position(pos), tok, sss, "2nd same name field"}
		}

		ttt.Fields[fnm] = val

		/* token.COMMA */
		pos, tok, sss = ps.lex.Next(skipNone)
		if tok == token.RBRACE {
			break
		}

		if tok != token.COMMA {
			return nil, &Error{ps.lex.Position(pos), tok, sss, "field separate need comma"}
		}
	}

	/**/
	return ttt, nil
}

func (ps *Parser) expectArray() (*SArray, *Error) {
	var pos token.Pos
	var tok token.Token
	var sss string

	/**/
	ary := &SArray{nil}

	for {
		pos, tok, sss = ps.lex.Next(skipNone)
		if tok == token.RBRACK {
			break
		} else {
			ps.lex.Back()
		}

		val, perr := ps.expectValue()
		if perr != nil {
			return nil, perr
		}

		ary.Vals = append(ary.Vals, val)

		/* token.COMMA */
		pos, tok, sss = ps.lex.Next(skipNone)
		if tok == token.RBRACK {
			break
		}

		if tok != token.COMMA {
			return nil, &Error{ps.lex.Position(pos), tok, sss, "element separate need comma"}
		}
	}

	/**/
	return ary, nil
}

func dumpArray(ary *SArray) {

	fmt.Printf("[ ")
	for _, vv := range ary.Vals {

		switch pv := vv.(type) {
		case *int64:
			fmt.Printf("int64:%v, ", *pv)

		case *float64:
			fmt.Printf("float64:%v, ", *pv)

		case *string:
			fmt.Printf("string:%q, ", *pv)

		default:
			fmt.Printf("other:%v, ", reflect.TypeOf(pv))
		}
	}

	fmt.Printf(" ]\n")

}

func dumpStuct(ary *SStruct) {
	fmt.Println("")
}

func (ps *Parser) Dump() {
	for _, exp := range ps.Expres {
		fmt.Printf("%s:", exp.Ident)

		switch pv := exp.Vval.(type) {
		case *int64:
			fmt.Printf("int64, %v\n", *pv)

		case *float64:
			fmt.Printf("float64, %v\n", *pv)

		case *string:
			fmt.Printf("string, %q\n", *pv)

		case *SArray:
			dumpArray(pv)

		case *SStruct:
			dumpStuct(pv)

		default:
			fmt.Printf("other, %v\n", reflect.TypeOf(pv))

		}
	}
}
